{ *********************************************************** }
{ *                    ksTools Library                      * }
{ *       Copyright (c) Sergey Kasandrov 1997, 2010         * }
{ *       -----------------------------------------         * }
{ *         http://sergworks.wordpress.com/kstools          * }
{ *********************************************************** }

unit TestInt;
{

  Delphi DUnit Test Case
  ----------------------
  This unit contains a skeleton test case class generated by the Test Case Wizard.
  Modify the generated code to correctly setup and call the methods from the unit
  being tested.

}

interface

uses
  TestFramework, Windows, Forms, Dialogs, Controls, Classes, SysUtils, Variants,
  Graphics, Messages, ksMath;

type
  TTestInt = class(TTestCase)
  private
    FValue1: TksInteger;
    FValue2: TksInteger;
    FValue3: TksInteger;
    FValue4: TksInteger;
    FValue5: TksInteger;
    FValue6: TksInteger;

    procedure CheckEqualValues(const A, B: TksInteger; const Comment: string = '');

    procedure TestAddValue(const A, B, R: array of LongWord;
                           AMinus, BMinus, RMinus: Integer);
    procedure TestAddLimb(const A, R: array of LongWord; Limb: LongWord;
                                AMinus, RMinus: Integer);

    procedure TestSubValue(const A, B, R: array of LongWord;
                           AMinus, BMinus, RMinus: Integer);
    procedure TestSubLimb(const A, R: array of LongWord; Limb: LongWord;
                                AMinus, RMinus: Integer);

    procedure TestMulValue(const A, B, R: array of LongWord;
                           AMinus, BMinus, RMinus: Integer);
    procedure TestDivModValue(const A, B, Q, R: array of LongWord;
                              AMinus, BMinus, QMinus, RMinus: Integer);
    procedure TestMulDivModValue(const A, B, R: array of LongWord;
                                 AMinus, BMinus, RMinus: Integer);

    procedure TestMulAddSubValue(const A: array of LongWord; Count: LongWord;
                                       AMinus: Integer);

    procedure TestMulLimb(const A, R: array of LongWord; Limb: LongWord;
                                AMinus, RMinus: Integer);

    procedure TestAddSubLimbs(const A: array of LongWord; Limb: LongWord;
                              const R: array of LongWord);
    procedure TestMulLimbs(const A: array of LongWord; Limb: LongWord;
                           const R: array of LongWord);

    procedure TestMulValues(const A, B, R: array of LongWord);
    procedure TestAddSubValues(const A, B, R: array of LongWord);
    procedure TestMulAddSubValues(const A: array of LongWord; Count: LongWord);
    procedure TestDivModValues(const A, B, Q, R: array of LongWord);
    procedure TestMulDivModValues(const A, B, R: array of LongWord);

    procedure TestString(const S: string; Value: array of LongWord;
                         Sign: Integer = 0);
  protected
    procedure SetUp; override;

  published
    procedure TestAddSubValueZero;
    procedure TestAddSubValueNoCarry;
    procedure TestAddSubValueCarry;

    procedure TestMulValueZero;
    procedure TestMulValueNoCarry;

    procedure TestMulAddSubValueRandom;

    procedure TestDivValue0;
    procedure TestDivValue1;
    procedure TestDivValue2;
    procedure TestDivValueSpecial;

    procedure TestMulDivModValueZero;
    procedure TestMulDivModValueMisc;
    procedure TestMulDivModValueRandom;
    procedure TestMulDivModValueSpecial;

    procedure AddSubLimbZero;
    procedure AddSubLimbNoCarry;

    procedure MulLimbZero;

    procedure TestStrings;
  end;

implementation

{ TestInt }

procedure TTestInt.SetUp;
begin
  Randomize;
end;

procedure TTestInt.CheckEqualValues(const A, B: TksInteger; const Comment: string);
var
  I: Integer;

begin
  CheckEquals(A.Data[0], B.Data[0],
      Format('%s Length: %d -- %d', [Comment, A.Data[0], B.Data[0]]));
  for I:= 1 to Abs(LongInt(A.Data[0])) do
    CheckEquals(A.Data[I], B.Data[I],
      Format('%s Data[%d]: %.8x -- %.8x', [Comment, I, A.Data[I], B.Data[I]]));
end;

(* === Addition Tests === *)

procedure TTestInt.TestAddValue(const A, B, R: array of LongWord;
                           AMinus, BMinus, RMinus: Integer);
begin
  FValue1.AssignData(A, AMinus);
  FValue2.AssignData(B, BMinus);
  FValue3.AssignData(R, RMinus);

// Check R = A + B
  FValue4:= FValue1 + FValue2;
  CheckEqualValues(FValue3, FValue4);

// Check A has not changed after addition
  FValue4.AssignData(A, AMinus);
  CheckEqualValues(FValue4, FValue1);

// Check B has not changed after addition
  FValue4.AssignData(B, BMinus);
  CheckEqualValues(FValue4, FValue2);

// SelfAdd: Check R = A + B
  FValue1.SelfAdd(FValue2);
  CheckEqualValues(FValue3, FValue1);

// SelfAdd: Check B has not changed after addition
  FValue4.AssignData(B, BMinus);
  CheckEqualValues(FValue4, FValue2);
end;

procedure TTestInt.TestAddLimb(const A, R: array of LongWord; Limb: LongWord;
                               AMinus, RMinus: Integer);
begin
  FValue1.AssignData(A, AMinus);
  FValue2.AssignData(R, RMinus);

// Check R = A + Limb
  FValue3:= FValue1 + Limb;
  CheckEqualValues(FValue2, FValue3);

// Check A has not changed after addition
  FValue3.AssignData(A, AMinus);
  CheckEqualValues(FValue3, FValue1);

// Check R = Limb + A
  FValue3:= Limb + FValue1;
  CheckEqualValues(FValue2, FValue3);

// Check A has not changed after addition
  FValue3.AssignData(A, AMinus);
  CheckEqualValues(FValue3, FValue1);

// SelfAdd: Check R = A + Limb
  FValue1.SelfAddCardinal(Limb);
  CheckEqualValues(FValue2, FValue1);
end;

(* === Subtraction Tests === *)

procedure TTestInt.TestSubValue(const A, B, R: array of LongWord;
                           AMinus, BMinus, RMinus: Integer);
begin
  FValue1.AssignData(A, AMinus);
  FValue2.AssignData(B, BMinus);
  FValue3.AssignData(R, RMinus);

// Check R = A - B
  FValue4:= FValue1 - FValue2;
  CheckEqualValues(FValue3, FValue4);

// Check A has not changed after subtraction
  FValue4.AssignData(A, AMinus);
  CheckEqualValues(FValue4, FValue1);

// Check B has not changed after subtraction
  FValue4.AssignData(B, BMinus);
  CheckEqualValues(FValue4, FValue2);

// SelfSub: Check R = A - B
  FValue1.SelfSub(FValue2);
  CheckEqualValues(FValue3, FValue1);

// SelfSub: Check B has not changed after subtraction
  FValue4.AssignData(B, BMinus);
  CheckEqualValues(FValue4, FValue2);
end;

procedure TTestInt.TestSubLimb(const A, R: array of LongWord; Limb: LongWord;
                               AMinus, RMinus: Integer);
begin
  FValue1.AssignData(A, AMinus);
  FValue2.AssignData(R, RMinus);

// Check R = A - Limb
  FValue3:= FValue1 - Limb;
  CheckEqualValues(FValue2, FValue3);

// Check A has not changed after subtraction
  FValue3.AssignData(A, AMinus);
  CheckEqualValues(FValue3, FValue1);

  FValue2.AssignData(R, -(RMinus + 1));

// Check -R = Limb - A
  FValue3:= Limb - FValue1;
  CheckEqualValues(FValue2, FValue3);

// Check A has not changed after subtraction
  FValue3.AssignData(A, AMinus);
  CheckEqualValues(FValue3, FValue1);

// SelfSub: Check R = A - Limb
  FValue1.SelfSubCardinal(Limb);
  FValue2.AssignData(R, RMinus);
  CheckEqualValues(FValue2, FValue1);
end;


procedure TTestInt.TestString(const S: string; Value: array of LongWord;
                              Sign: Integer = 0);
var
  S1: string;
  I: Integer;

begin
  if not FValue1.FromString(S) then
    raise Exception.Create('FromString failed');
  FValue2.AssignData(Value, Sign);
  if FValue1.IsZero or (Length(Value) > 0) then
    CheckEqualValues(FValue2, FValue1);
  if Length(S) = 0 then Exit;
  I:= 1;
  if Integer(FValue1.Data[0]) < 0 then Inc(I);
  if (S[I] <> '$') then begin
    S1:= FValue1.AsString;
    CheckEquals(S, S1);
  end;
end;

procedure TTestInt.TestStrings;
begin
  TestString('1234', [1234]);
  TestString('$1234567890ABCDEF', [$90ABCDEF, $12345678]);
  TestString('-$1234567890ABCDEF', [$90ABCDEF, $12345678], -1);
  TestString('123456789098765432101234567890', []);
  TestString('-123456789098765432101234567890', []);
end;

(* === Multiplication Tests === *)

procedure TTestInt.TestMulValue(const A, B, R: array of LongWord;
                                AMinus, BMinus, RMinus: Integer);
begin
  FValue1.AssignData(A, AMinus);
  FValue2.AssignData(B, BMinus);
  FValue3.AssignData(R, RMinus);

// Check R = A * B
  FValue4:= FValue1 * FValue2;
  CheckEqualValues(FValue3, FValue4);

// Check A has not changed after multiplication
  FValue4.AssignData(A, AMinus);
  CheckEqualValues(FValue4, FValue1);

// Check B has not changed after multiplication
  FValue4.AssignData(B, BMinus);
  CheckEqualValues(FValue4, FValue2);
end;

procedure TTestInt.TestMulLimb(const A, R: array of LongWord; Limb: LongWord;
                               AMinus, RMinus: Integer);
begin
  FValue1.AssignData(A, AMinus);
  FValue2.AssignData(R, RMinus);

// Check R = A * Limb
  FValue3:= FValue1 * Limb;
  CheckEqualValues(FValue2, FValue3);

// Check A has not changed after multiplication
  FValue3.AssignData(A, AMinus);
  CheckEqualValues(FValue3, FValue1);

// Check R = Limb * A
  FValue3:= Limb * FValue1;
  CheckEqualValues(FValue2, FValue3);

// Check A has not changed after multiplication
  FValue3.AssignData(A, AMinus);
  CheckEqualValues(FValue3, FValue1);
end;

procedure TTestInt.TestDivModValue(const A, B, Q, R: array of LongWord;
                              AMinus, BMinus, QMinus, RMinus: Integer);
begin
  FValue1.AssignData(A, AMinus);
  FValue2.AssignData(B, BMinus);
  FValue3:= FValue1 div FValue2;

// Check Quotient
  if Length(Q) > 0 then begin
    FValue5.AssignData(Q, QMinus);
    CheckEqualValues(FValue5, FValue3, 'Quotient');
  end;

// Check Dividend has not changed after DIV
  FValue5.AssignData(A, AMinus);
  CheckEqualValues(FValue5, FValue1);

// Check Divisor has not changed after DIV
  FValue5.AssignData(B, BMinus);
  CheckEqualValues(FValue5, FValue2);

  FValue4:= FValue1 mod FValue2;

// Check Remainder
  if Length(R) > 0 then begin
    FValue5.AssignData(R, RMinus);
    CheckEqualValues(FValue5, FValue4, 'Remainder');
  end;

// Check Dividend has not changed after MOD
  FValue5.AssignData(A, AMinus);
  CheckEqualValues(FValue5, FValue1);

// Check Divisor has not changed after MOD
  FValue5.AssignData(B, BMinus);
  CheckEqualValues(FValue5, FValue2);

// Check A = B * Q + R;
  FValue5:= FValue2 * FValue3 + FValue4;
  CheckEqualValues(FValue1, FValue5);
end;

procedure TTestInt.TestMulAddSubValue(const A: array of LongWord;
                       Count: LongWord; AMinus: Integer);
var
  TmpCount: LongWord;

begin
  FValue1.AssignData(A, AMinus);
  FValue2.Assign(FValue1);
  TmpCount:= Count - 1;
  repeat
    FValue2:= FValue1 + FValue2;
    Dec(TmpCount);
  until TmpCount = 0;
  FValue3:= FValue1 * Count;
  CheckEqualValues(FValue3, FValue2);
  TmpCount:= Count - 1;
  repeat
    FValue2:= FValue2 - FValue1;
    Dec(TmpCount);
  until TmpCount = 0;
  CheckEqualValues(FValue1, FValue2);
end;

procedure TTestInt.TestMulAddSubValueRandom;
var
  Count, I: Integer;
  Value: array[0..4] of LongWord;

begin
  Count:= 10000;
  repeat
    for I:= Low(Value) to High(Value) do
      Value[I]:= 4 * Random($40000000) + Random(4);
    if Value[High(Value)] = 0 then Inc(Value[High(Value)]);

    TestMulAddSubValues(Value, Count);

    Count:= Count div 2;
  until Count < 2;
end;

procedure TTestInt.TestMulAddSubValues(const A: array of LongWord;
                                       Count: LongWord);
begin
  TestMulAddSubValue(A, Count, 0);
  TestMulAddSubValue(A, Count, -1);
end;

procedure TTestInt.TestMulDivModValue(const A, B, R: array of LongWord;
                   AMinus, BMinus, RMinus: Integer);
begin
  FValue1.AssignData(A, AMinus);
  FValue2.AssignData(B, BMinus);
  FValue3.AssignData(R, RMinus);
  FValue4:= FValue1 * FValue2 + FValue3;

  FValue5:= FValue4 div FValue1;
  CheckEqualValues(FValue2, FValue5);

  FValue6:= FValue4 mod FValue1;
  CheckEqualValues(FValue3, FValue6);
end;

procedure TTestInt.TestMulDivModValues(const A, B, R: array of LongWord);
begin
  TestMulDivModValue(A, B, R, 0, 0, 0);      // 5 * 2 + 4 = 14,
                                             // 14 div 5 = 2,
                                             // 14 mod 5 = 4
  TestMulDivModValue(A, B, R, -1, 0, -1);    // (-5) * 2 - 4 = -14,
                                             // (-14) div (-5) = 2,
                                             // (-14) mod (-5) = -4
  TestMulDivModValue(A, B, R, 0, -1, -1);    // 5 * (-2) - 4 = -14,
                                             // (-14) div 5 = -2,
                                             // (-14) mod 5 = -4
  TestMulDivModValue(A, B, R, -1, -1, 0);    // (-5) * (-2) + 4 = 14
                                             // 14 div (-5) = -2
                                             // 14 mod (-5) = 4
end;

procedure TTestInt.TestMulDivModValueZero;
begin
  TestMulDivModValues([$11], [0], [$1]);
  TestMulDivModValues([$111, $222], [0], [$123]);
  TestMulDivModValues([$111, $222], [0], [$123, $22]);
end;

procedure TTestInt.TestMulLimbs(const A: array of LongWord; Limb: LongWord;
                                const R: array of LongWord);
begin
  TestMulLimb(A, R, Limb, 0, 0);      // A * Limb = R
  TestMulLimb(A, R, Limb, -1, -1);    // -A * Limb = -R
end;

procedure TTestInt.TestMulValues(const A, B, R: array of LongWord);
begin
  TestMulValue(A, B, R, 0, 0, 0);
  TestMulValue(A, B, R, 0, -1, -1);
  TestMulValue(A, B, R, -1, 0, -1);
  TestMulValue(A, B, R, -1, -1, 0);
  TestMulValue(B, A, R, 0, 0, 0);
  TestMulValue(B, A, R, 0, -1, -1);
  TestMulValue(B, A, R, -1, 0, -1);
  TestMulValue(B, A, R, -1, -1, 0);
end;

procedure TTestInt.TestAddSubValues(const A, B, R: array of LongWord);
begin
  TestAddValue(A, B, R, 0, 0, 0);         // A + B = R
  TestAddValue(A, B, R, -1, -1, -1);      // -A + (-B) = -R
  TestAddValue(B, A, R, 0, 0, 0);         // B + A = R
  TestAddValue(B, A, R, -1, -1, -1);      // -B + (-A) = -R
  TestAddValue(A, R, B, 0, -1, -1);       // A + (-R) = -B
  TestAddValue(A, R, B, -1, 0, 0);        // -A + R = B
  TestAddValue(R, A, B, 0, -1, 0);        // R + (-A) = B
  TestAddValue(R, A, B, -1, 0, -1);       // -R + A = -B
  TestAddValue(B, R, A, 0, -1, -1);       // B + (-R) = -A
  TestAddValue(B, R, A, -1, 0, 0);        // -B + R = A
  TestAddValue(R, B, A, 0, -1, 0);        // R + (-B) = A
  TestAddValue(R, B, A, -1, 0, -1);       // -R + B = -A

  TestSubValue(R, A, B, 0, 0, 0);         // R - A = B
  TestSubValue(R, B, A, 0, 0, 0);         // R - B = A
  TestSubValue(R, A, B, -1, -1, -1);      // -R - (-A) = -B
  TestSubValue(R, B, A, -1, -1, -1);      // -R - (-B) = -A

  TestSubValue(A, B, R, 0, -1, 0);        // A - (-B) = R
  TestSubValue(A, B, R, -1, 0, -1);       // -A - B = -R
  TestSubValue(A, R, B, 0, 0, -1);        // A - R = -B
  TestSubValue(A, R, B, -1, -1, 0);       // -A - (-R) = B

  TestSubValue(B, A, R, 0, -1, 0);        // B - (-A) = R
  TestSubValue(B, A, R, -1, 0, -1);       // -B - A = -R
  TestSubValue(B, R, A, 0, 0, -1);        // B - R = -A
  TestSubValue(B, R, A, -1, -1, 0);       // -B - (-R) = A
end;

procedure TTestInt.TestAddSubLimbs(const A: array of LongWord; Limb: LongWord;
                                   const R: array of LongWord);
begin
  TestAddLimb(A, R, Limb, 0, 0);        // A + Limb = R;
  TestAddLimb(R, A, Limb, -1, -1);      // -R + Limb = -A;
  TestSubLimb(R, A, Limb, 0, 0);        // R - Limb = A;
  TestSubLimb(A, R, Limb, -1, -1);      // -A - Limb = -R;
end;

procedure TTestInt.TestAddSubValueZero;
begin
  TestAddSubValues([0], [0], [0]);
  TestAddSubValues([$AAAAAAAA], [0], [$AAAAAAAA]);
  TestAddSubValues([$AAAAAAAA, $AAAAAAAA], [0], [$AAAAAAAA, $AAAAAAAA]);
  TestAddSubValues([$AAAAAAAA, $22222222], [0], [$AAAAAAAA, $22222222]);
end;

procedure TTestInt.TestAddSubValueNoCarry;
begin
  TestAddSubValues([$AAAAAAAA],
                   [$11111111],
                   [$BBBBBBBB]);

  TestAddSubValues([$AAAAAAAA, $55555555],
                   [$11111111],
                   [$BBBBBBBB, $55555555]);

  TestAddSubValues([$AAAAAAAA, $55555555],
                   [$11111111, $22222222],
                   [$BBBBBBBB, $77777777]);

  TestAddSubValues([$99999999, $55555555],
                   [$11111111],
                   [$AAAAAAAA, $55555555]);

end;

procedure TTestInt.AddSubLimbZero;
begin
  TestAddSubLimbs([0], 0, [0]);
  TestAddSubLimbs([0], 1, [1]);
  TestAddSubLimbs([1], 0, [1]);
  TestAddSubLimbs([$11111111, $22222222], 0, [$11111111, $22222222]);
end;

procedure TTestInt.AddSubLimbNoCarry;
begin
  TestAddSubLimbs([$AAAAAAAA], $11111111, [$BBBBBBBB]);
  TestAddSubLimbs([$AAAAAAAA, $55555555],
                   $11111111,
                  [$BBBBBBBB, $55555555]);

end;

procedure TTestInt.TestAddSubValueCarry;
begin
  TestAddSubValues([$AAAAAAAA, $11111111],
                   [$55555556],
                   [$00000000, $11111112]);

  TestAddSubValues([$AAAAAAAA, $33333333],
                   [$55555556, $CCCCCCCC],
                   [$00000000, $00000000, 1]);

  TestAddSubValues([$AAAAAAAA, $FFFFFFFF],
                   [$55555556],
                   [$00000000, $00000000, 1]);

  TestAddSubValues([$AAAAAAAA, $FFFFFFFF, $FFFFFFFF],
                   [$55555556],
                   [$00000000, $00000000, $00000000, 1]);

  TestAddSubValues([$FFFFFFFF, $55555554],
                   [$AAAAAAAB],
                   [$AAAAAAAA, $55555555]);

  TestAddSubValues([$FFFFFFFF],
                   [$AAAAAAAB],
                   [$AAAAAAAA, 1]);

  TestAddSubValues([$FFFFFFFF, $FFFFFFFF],
                   [$AAAAAAAB],
                   [$AAAAAAAA, 0, 1]);

  TestAddSubValues([$AAAAAAAA, $22222222],
                   [$55555556],
                   [$00000000, $22222223]);

  TestAddSubValues([$AAAAAAAA, $22222222],
                   [$55555556, $DDDDDDDD],
                   [$00000000, $00000000, 1]);

  TestAddSubValues([$FFFFFFFF, $22222221],
                   [$AAAAAAAB],
                   [$AAAAAAAA, $22222222]);

end;

procedure TTestInt.TestMulValueZero;
begin
  TestMulValues([0], [0], [0]);
  TestMulValues([$AAAAAAAA], [0], [0]);
  TestMulValues([$AAAAAAAA, $AAAAAAAA], [0], [0]);
end;

procedure TTestInt.MulLimbZero;
begin
  TestMulLimbs([0], 0, [0]);
  TestMulLimbs([0], 1, [0]);
  TestMulLimbs([1], 0, [0]);
  TestMulLimbs([$AAAAAAAA, $AAAAAAAA], 0, [0]);
end;

procedure TTestInt.TestMulValueNoCarry;
begin
  TestMulValues([$0000AAAA, $0000BBBB],
                [$00001111],
                [$0B609F4A, $0C83E26B]);

  TestMulValues([$00003333, $00001111],
                [$00004444, $00002222],
                [$0DA7258C, $0B609F4A, $02468642]);

  TestMulValues([0, 1], [0, 0, 1], [0, 0, 0, 1]);

end;

procedure TTestInt.TestDivModValues(const A, B, Q, R: array of LongWord);
begin
  TestDivModValue(A, B, Q, R, 0, 0, 0, 0);      // A div B = Q + R
  TestDivModValue(A, B, Q, R, -1, 0, -1, -1);   // -A div B = -Q - R
  TestDivModValue(A, B, Q, R, 0, -1, -1, 0);    // A div (-B) = -Q + R
  TestDivModValue(A, B, Q, R, -1, -1, 0, -1);   // -A div (-B) = Q - R
end;

procedure TTestInt.TestDivValue0;
begin
  TestDivModValues([0],[1],[0],[0]);
  TestDivModValues([$1224], [$12], [$102], [0]);
  TestDivModValues([$1234], [$12], [$102], [$10]);
end;

procedure TTestInt.TestDivValue1;
begin
  TestDivModValues([$0B609F4A, $0C83E26B],
                   [$00001111],
                   [$0000AAAA, $0000BBBB],
                   [0]);
  TestDivModValues([$0B609F5B, $0C83E26B],
                   [$00001111],
                   [$0000AAAA, $0000BBBB],
                   [$11]);
  TestDivModValues([0, 0, 1], [0, 1], [0, 1], [0]);
  TestDivModValues([2, 0, 1], [0, 1], [0, 1], [2]);//, 0, 0, 0, 0);
//  TestDivModValue( [1, 0, 0, 1], [0, 0, 1], [0, 1], [1], 0, 0, 0, 0);
end;

procedure TTestInt.TestDivValue2;
begin
  TestDivModValues([$22222222, $55555555, $80000000],
                   [$33333333, $80000000],
                   [0, 1],
                   [$22222222, $22222222]);
end;

procedure TTestInt.TestMulDivModValueMisc;
begin
  TestMulDivModValues([$44444444, $BBBBBBBB, $AAAAAAAA],
                      [$FFFF],
                      [$22222222, $FFFFFFFF, $77777777]);

  TestMulDivModValues([$44444444, $BBBBBBBB, $AAAAAAAA],
                      [$FFFF, $EEEEEEEE],
                      [$22222222, $FFFFFFFF, $77777777]);
end;

procedure TTestInt.TestMulDivModValueRandom;
var
  Count, I: Integer;
  Quotient: array[0..2] of LongWord;
  Divisor: array[0..2] of LongWord;
  Remainder: array[0..1] of LongWord;

begin
  Count:= 10000;
  repeat
    for I:= Low(Quotient) to High(Quotient) do
      Quotient[I]:= 4 * Random($40000000) + Random(4);
    if Quotient[High(Quotient)] = 0 then Inc(Quotient[High(Quotient)]);

    for I:= Low(Divisor) to High(Divisor) do
      Divisor[I]:= 4 * Random($40000000) + Random(4);
    if Divisor[High(Divisor)] = 0 then Inc(Divisor[High(Divisor)]);

    for I:= Low(Remainder) to High(Remainder) do
      Remainder[I]:= 4 * Random($40000000) + Random(4);
    if Remainder[High(Remainder)] = 0 then Inc(Remainder[High(Remainder)]);

    TestMulDivModValues(Divisor, Quotient, Remainder);

    Dec(Count);
  until Count = 0;
end;

// 'wrong guess' test (QGuess = Q + 1)
procedure TTestInt.TestMulDivModValueSpecial;
begin
  TestMulDivModValues([$00000004, $00000000, $80000000],
                      [$FFFFFFFF],
                      [$00000004, $FFFFFFFC, $7FFFFFFF]);
  TestMulDivModValues([$00000004, $00000000, $80000000],
                      [$7FFFFFFF],
                      [$00000004, $FFFFFFFE, $7FFFFFFF]);
end;

// 'wrong guess' test (QGuess = Q + 1)
procedure TTestInt.TestDivValueSpecial;
begin
  TestDivModValues([$00000000, $00000000, $00000000, $80000000],
                   [$00000004, $00000000, $80000000],
                   [$FFFFFFFF],
                   [$00000004, $FFFFFFFC, $7FFFFFFF]);

  TestDivModValues([$00000000, $00000000, $00000000, $40000000],
                   [$00000004, $00000000, $80000000],
                   [$7FFFFFFF],
                   [$00000004, $FFFFFFFE, $7FFFFFFF]);
end;

initialization
  // Register any test cases with the test runner
  RegisterTest(TTestInt.Suite);
end.

